﻿#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace JH
{
    /// <summary>
    ///  分割线类型
    /// </summary>
    public enum DivisionLineType
    {
        /// <summary>
        ///  分割线在顶部或右侧
        /// </summary>
        TopOrRight,

        /// <summary>
        ///  分割线在底部或左侧
        /// </summary>
        BottomOrLeft,

        /// <summary>
        ///  分割线在中间
        /// </summary>
        Middle
    }

    /// <summary>
    ///  分割线的基类
    /// </summary>
#if ODIN_INSPECTOR
    [ReadOnly]
#endif
    public abstract class BasicDivisionLine : BasicMono<Vector2>
        , IDivisionLine
    {
        /// <summary>
        ///  分割线的类型
        /// </summary>
#if ODIN_INSPECTOR
        [LabelText("分割线类型")] 
#endif
        public DivisionLineType divisionLineType;

        /// <summary>
        ///  分割线的线条
        /// </summary>
        [SerializeField] protected Image lineImage;

        /// <summary>
        ///  分割线的标签
        /// </summary>
        [SerializeField] protected TextMeshProUGUI label;

        [SerializeField]
#if ODIN_INSPECTOR
        [LabelText("标签保留小数位数")]
#endif
        private int format = 2;

        /// <summary>
        ///  分割线标签的格式化字符串
        /// </summary>
        private string _formatString;

        /// <summary>
        ///  分割线标签的格式化字符串
        /// </summary>
        private string FormatString
        {
            get
            {
                if (_formatString == null)
                {
                    _formatString = "0.";
                    for (int i = 0; i < format; i++)
                        _formatString += "#";
                }

                return _formatString;
            }
        }

        /// <summary>
        ///  分割线标签的缓存
        /// </summary>
        private static Dictionary<float, string> _labelCache = new();

        /// <summary>
        ///  分割线标签的缓存最大容量
        /// </summary>
        private const int MaxCacheSize = 1000;

        /// <summary>
        ///  是否展示分割线
        /// </summary>
        [SerializeField]
#if ODIN_INSPECTOR
        [LabelText("展示分割线")]
#endif
        private bool showLine;

        /// <summary>
        ///  是否展示分割线标签
        /// </summary>
        [SerializeField]
#if ODIN_INSPECTOR
        [LabelText("展示分割线标签")]
#endif
        private bool showLabel;

        /// <summary>
        ///  图表得边界处理器
        /// </summary>
        private BoundaryHandler _boundaryHandler;

        /// <summary>
        ///  获取图表的边界处理器
        /// </summary>
        public BoundaryHandler BoundaryHandler
        {
            get => _boundaryHandler ??= this.GetChartComp<BoundaryHandler, Vector2>();
            set => _boundaryHandler = value;
        }

        [SerializeField]
#if ODIN_INSPECTOR
        [LabelText("当前分割线对应的值")]
#endif
        private float value;

        /// <summary>
        ///  当前分割线对应的值
        /// </summary>
        public float Value
        {
            get => value;
            set
            {
                // 设置分割线的位置
                OnSetValue(value);

                // 根据是否展示分割线，来决定是否显示分割线
                ShowLine = showLine;

                //根据是否展示分割线标签，来决定是否显示标签的文本
                ShowLabel = showLabel;

                // 如果有标签,设置标签的文本
                if (label)
                {
                    var key = Mathf.RoundToInt(value * Mathf.Pow(10, format)) / Mathf.Pow(10, format);
                    if (_labelCache.Count > MaxCacheSize) _labelCache.Clear();
                    if (!_labelCache.TryGetValue(key, out var labelText))
                    {
                        labelText = key.ToString(FormatString);
                        _labelCache[key] = labelText;
                    }

                    label.text = labelText;
                }

                this.value = value;
            }
        }

        /// <summary>
        ///  当设置分割线对应的值时调用
        /// </summary>
        /// <param name="newValue">新得分割线对应的值</param>
        protected abstract void OnSetValue(float newValue);

        /// <summary>
        ///  是否展示分割线
        /// </summary>
        public bool ShowLine
        {
            get => showLine;
            set
            {
                showLine = value;
                if (lineImage == null) return;
                lineImage.enabled = value;
            }
        }

        /// <summary>
        ///  是否展示分割线标签
        /// </summary>
        public bool ShowLabel
        {
            get => showLabel;
            set
            {
                showLabel = value;
                if (label == null) return;
                label.enabled = value;
            }
        }

        protected override void OnValidate()
        {
            lineImage = GetComponent<Image>();
            label = GetComponentInChildren<TextMeshProUGUI>(true);
            RefreshChart();
        }
    }
}